
using System;

using Galaxium.Core;
using Galaxium.Protocol.Xmpp.Library;
using L=Galaxium.Protocol.Xmpp.Library;
using Galaxium.Protocol.Xmpp.Library.Core;
using Galaxium.Protocol.Xmpp.Library.Extensions.Disco;

using Gtk;
using Glade;

namespace Galaxium.Protocol.Xmpp.GtkGui
{
	public class MucListWindow
	{
		private L.Client _client;
		
		private string _domain;
		private JabberID _current_selection;
		
		[Widget] private Window window;
		[Widget] private Entry server_entry;
		[Widget] private TreeView treeview;
				
		[Widget] private Label description_label;
		[Widget] private Label public_label;
		[Widget] private Label members_only_label;
		[Widget] private Label moderated_label;
		[Widget] private Label anonymous_label;
		[Widget] private Label secured_label;
		[Widget] private Label persistent_label;
		[Widget] private Alignment url_wrapper;
		private LinkButton log_link_button;
		[Widget] private Label occupants_label;
		[Widget] private Label subject_label;
		
		[Widget] private Button join_button;
		[Widget] private Button refresh_button;
		[Widget] private Button bookmark_button;
		
		public MucListWindow (L.Client client, JabberID server)
		{
			ThrowUtility.ThrowIfNull ("client", client);
			_client = client;
			var gxml = new XML (null, "MucListWindow.glade", null, null);
			gxml.Autoconnect (this);
			
			log_link_button = new LinkButton (String.Empty);
			log_link_button.Xalign = 0f;
			url_wrapper.Add (log_link_button);
			
			server_entry.Activated += HandleEntryActivated;
			refresh_button.Clicked += HandleEntryActivated;
			
			bookmark_button.Sensitive = false;
			join_button.Clicked += HandleJoinClicked;
			
			treeview.AppendColumn ("ID", new CellRendererText (), "text", 0);
			treeview.AppendColumn ("Name", new CellRendererText (), "text", 1);
			treeview.Selection.Mode = SelectionMode.Single;
			treeview.Selection.Changed += HandleSelectionChanged;
			
			server_entry.Text = (string) server ?? String.Empty;
			server_entry.Activate ();
			
			window.ShowAll ();
		}

		void HandleJoinClicked(object sender, EventArgs e)
		{
			var session = SessionUtility.ActiveSession as XmppSession;
			session.AddConference (_current_selection, true);
		}

		void HandleSelectionChanged (object sender, EventArgs e)
		{
			TreeIter iter;
			if (treeview.Selection.GetSelected (out iter)) {
				var node = treeview.Model.GetValue (iter, 0) as String;
				_current_selection = new JabberID (node, _domain, null);
				var request = new InfoRequest (_client, _current_selection, null);
				request.ErrorEvent += HandleRoomError;
				request.ReceivedEvent += HandleReceived;
				request.Request ();
			}
			else {
				_current_selection = null;
				
				description_label.Text = "--- nothing selected ---";
				public_label.Text = "--- nothing selected ---";
				members_only_label.Text = "--- nothing selected ---";
				moderated_label.Text = "--- nothing selected ---";
				anonymous_label.Text = "--- nothing selected ---";
				secured_label.Text = "--- nothing selected ---";
				persistent_label.Text = "--- nothing selected ---";
				log_link_button.Label = "--- nothing selected ---";
				occupants_label.Text = "--- nothing selected ---";
				subject_label.Text = "--- nothing selected ---";
				
				description_label.Sensitive = false;
				public_label.Sensitive = false;
				members_only_label.Sensitive = false;
				moderated_label.Sensitive = false;
				anonymous_label.Sensitive = false;
				secured_label.Sensitive = false;
				persistent_label.Sensitive = false;
				log_link_button.Sensitive = false;
				occupants_label.Sensitive = false;
				subject_label.Sensitive = false;
			}
		}

		void HandleReceived (object sender, EventArgs e)
		{
			var request = sender as InfoRequest;
			
			if (_current_selection != request.Jid) return;
			
			var info = new RoomInfo (request.Result);
						
			Application.Invoke ((s, args) => {
				description_label.Text = info.Description ?? String.Empty;
				public_label.Text = info.IsPublic ? "Yes" : "No";
				members_only_label.Text = info.IsMembersOnly ? "Yes" : "No";
				moderated_label.Text = info.IsModerated ? "Yes" : "No";
				anonymous_label.Text = info.IsNonAnonymous ? "No" : "Yes";
				secured_label.Text = info.IsPasswordProtected ? "Yes" : "No";
				persistent_label.Text = info.IsPersistent ? "Yes" : "No";
				log_link_button.Label = info.LogUrl ?? "no log";
				log_link_button.Uri = info.LogUrl ?? String.Empty;
				var num = info.Occupants;
				occupants_label.Text = num.HasValue ? num.Value.ToString () : "unknown";
				subject_label.Text = info.Subject;
				
				description_label.Sensitive = true;
				public_label.Sensitive = true;
				members_only_label.Sensitive = true;
				moderated_label.Sensitive = true;
				anonymous_label.Sensitive = true;
				secured_label.Sensitive = true;
				persistent_label.Sensitive = true;
				log_link_button.Sensitive = true;
				occupants_label.Sensitive = true;
				subject_label.Sensitive = true;
			});
		}

		void HandleRoomError (object sender, StanzaErrorEventArgs e)
		{
			// TODO: error handling
		}
		
		void HandleEntryActivated (object sender, EventArgs e)
		{
			if (server_entry.Text == String.Empty) return;
			
			_domain = server_entry.Text;
			
			treeview.Model = null;
			
			var server_request = new InfoRequest (_client, _domain, null);
			server_request.ReceivedEvent += HandleInfoReceived;
			server_request.ErrorEvent += (s, a) => {
				// TODO: error dialog
			};
			server_request.Request ();
		}

		void HandleInfoReceived (object sender, EventArgs e)
		{
			var request = sender as InfoRequest;
			var info = request.Result;
			
			foreach (var identity in info.Identities) {
				if (identity.Category == "directory" && identity.Type == "chatroom" ||
				    identity.Category == "conference" && identity.Type == "text") {
					var rooms_request = new ItemsRequest (_client, request.Jid, null);
					rooms_request.ReceivedEvent += HandleItemsReceivedEvent;
					rooms_request.ErrorEvent += (s, a) => {
						// TODO: error dialog
					};
					rooms_request.Request ();				
					return;
				}
			}
			
			// TODO: error dialog - not a chatroom service
		}

		void HandleItemsReceivedEvent (object sender, EventArgs e)
		{
			var request = sender as ItemsRequest;
			var items = request.Result;
			
			Application.Invoke ((s, a) => {
				var model = new ListStore (typeof (String), typeof (String));
				foreach (var item in items)
					model.AppendValues (item.Jid.Node, item.Name);
				model.DefaultSortFunc = (m, iter1, iter2) =>
					(m.GetValue (iter1, 0) as String).CompareTo (m.GetValue (iter2, 0) as String);
				model.SetSortColumnId (-1, SortType.Ascending);
				treeview.Model = model;
			});
		}
	}
}
